# -*- coding: utf-8 -*-
import cgi
import uuid
import logging

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db

import dbmodel
import yamlhelper
import handler
from mymodel import NotUniqueError


class MainHandler(handler.Handler):
    def get(self):
		logging.debug("Someone tried to get /")
		self.response.set_status(204)

class InsertHandler(handler.Handler):
	def post(self):
		
		if not self.requiredParams('type', 'sID'):
			logging.info("Required param missing in insert: "+str(self.params))
			return

		data = self.request.body
		
		typ = self.params['type']
		try:
			obj = dbmodel.types[typ].insert(data, self.user)
		except KeyError:
			logging.info("Invalid type given in insert: "+typ)
			self.response.set_status(400, "Invalid type, "+typ)
			return
		except NotUniqueError, e:
			logging.info("Key not unique: "+e.key)
			self.response.set_status(400, "Key not unique: "+e.key)
			return

		self.response.out.write("---\n")
		self.response.out.write("key: ")
		self.response.out.write(str(obj.key()))

class GetHandler(handler.Handler):
	def get(self):
		if not self.requiredParams('type', 'key'):
			return

		try:
			key = db.Key(self.params['key'])
		except db.BadKeyError:
			self.response.set_status(400, "Key: "+self.params['key']+" invalid")
			return
		
		typ = self.params['type']
		try:
			obj = dbmodel.types[typ].get(key)
		except KeyError:
			self.response.set_status(400, "Invalid type, "+typ)
			return
		except db.KindError:
			self.response.set_status(400, "No "+typ+" with key "+self.params['key'])
			return

		self.response.out.write("---\n")
		self.response.out.write(obj.dump())


class LoginHandler(handler.Handler):
	def post(self):
		logging.debug("Someone tried to login")
		
		if not self.requiredParams('username'):
			return

		data = self.request.body
		data = yamlhelper.loadData(data)

		query = dbmodel.User.gql("WHERE username = '%s'" % self.params['username'])

		user = query.get()

		if not user:
			logging.info("Bad username")
			self.response.set_status(400, "Bad username or password")
			return

		try:
			if user.password != data['password']:
				logging.info("Bad password")
				self.response.set_status(400, "Bad username or password")
				return
		except KeyError:
			logging.info("No password")
			self.response.set_status(400, "No password given")
			return

		#Make sure the session id isn't already in use
		sID = str(uuid.uuid4())
		query = dbmodel.User.gql("WHERE currentSID = '%s'" % sID)
		while query.count() > 0:
			sID = str(uuid.uuid4())
			query = dbmodel.User.gql("WHERE currentSID = '%s'" % sID)
		
		user.currentSID = sID
		user.put()

		body = user.dump()

		self.response.out.write(body)


class SearchHandler(handler.Handler):
	def post(self):
		if not self.requiredParams('type'):
			return

		typ = self.params['type']
		try:
			keys = dbmodel.types[typ].search(self.request.body)
		except KeyError:
			self.response.set_status(400, "Invalid type, "+typ)
			return

		body = yamlhelper.dumpObj(keys)

		self.response.out.write(body)


class UpdateHandler(handler.Handler):
	def post(self):

		if not self.requiredParams('key', 'type', 'sID'):
			logging.info("Required param missing in insert: "+str(self.params))
			return

		data = self.request.body

		typ = self.params['type']
		try:
			obj = dbmodel.types[typ].get(self.params["key"])
			obj.update(data, self.user)
		except KeyError:
			logging.info("Invalid type given in insert: "+typ)
			self.response.set_status(400, "Invalid type, "+typ)
			return
		except NotUniqueError, e:
			logging.info("Key not unique: "+e.key)
			self.response.set_status(400, "Key not unique: "+e.key)
			return

		self.response.set_status(200)


class SubStructSearchHandler(handler.Handler):
	def post(self):

		data = self.request.body

		fp = yamlhelper.loadData(data)

		query = dbmodel.Compound.all(keys_only=True)
		for i in fp:
			query.filter("fingerprint =", i)

		logging.info(str(fp))
		logging.info(query)

		keys = query.fetch(100)
		keys = [str(i) for i in keys]
		logging.info(keys)

		self.response.out.write(yamlhelper.dumpObj(keys))


class GetReactionsHandler(handler.Handler):
	def get(self):
		if not self.requiredParams('key'):
			return

		try:
			key = db.Key(self.params['key'])
		except db.BadKeyError:
			self.response.set_status(400, "Key: "+self.params['key']+" invalid")
			return

		#Return the reactions where this is a reactant
		c = dbmodel.Compound.get(key)
		query = db.GqlQuery('SELECT * FROM Reactant WHERE compound = :1', c)
		reactants = query.fetch(100)
		
		#Return the reactions where this is a product
		c = dbmodel.Compound.get(key)
		query = db.GqlQuery('SELECT * FROM Product WHERE compound = :1', c)
		products = query.fetch(100)

		keysReactant = [str(r.reaction.key()) for r in reactants]
		keysProduct = [str(p.reaction.key()) for p in products]

		logging.info(str(keysReactant)+str(keysProduct))
		
		resp = {'reactant': keysReactant, 'product': keysProduct}
		body = yamlhelper.dumpObj(resp)
		
		self.response.out.write(body)

class DeleteAllHandler(handler.Handler):
	def get(self):
		if self.request.url.find("origindb-test")==-1 and self.request.url.find(":8080")==-1:
			self.response.set_status(404)
		
		if not self.requiredParams('type'):
			return

		typ = self.params['type']
		query = dbmodel.types[typ].all()
		for i in query.fetch(1000):
			logging.info("deleting key"+str(i.key()))
			i.delete()
		
		self.response.set_status(200)


class LogoutHandler(handler.Handler):
	def get(self):
		if not self.requiredParams('sID'):
			return
		
		self.user.currentSID = ''
		self.response.set_status(200)


application = webapp.WSGIApplication([('/', MainHandler),
									  ('/insert', InsertHandler),
									  ('/get', GetHandler),
									  ('/login', LoginHandler),
									  ('/logout', LogoutHandler),
									  ('/search', SearchHandler),
									  ('/update', UpdateHandler),
									  ('/subStructSearch', SubStructSearchHandler),
									  ('/getReactions', GetReactionsHandler),
									  ('/deleteAll', DeleteAllHandler)
									  ], debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()